package hotel.quartz.oversea.job.switchs;

import com.alibaba.fastjson.JSON;
import hotel.base.oversea.constant.CommonConstants;
import hotel.base.oversea.constant.CommonUrlConstants;
import hotel.base.oversea.constant.MeituanConstants;
import hotel.base.oversea.constant.enums.MessageEnums;
import hotel.base.oversea.constant.quartz.UrlSwitchsEnums;
import hotel.base.oversea.utils.DateUtil;
import hotel.base.oversea.utils.GsonUtils;
import hotel.base.oversea.utils.Result;
import hotel.base.oversea.utils.SendUtils;
import hotel.base.oversea.vo.switchs.BatchPushRoomDataVo;
import hotel.quartz.oversea.config.service.RedisService;
import hotel.quartz.oversea.config.service.SwitchRoomPriceService;
import hotel.quartz.oversea.job.base.BaseJob;
import hotel.quartz.oversea.job.task.StartMtApiGoodsPriStatUpdateInfoTask;
import hotel.quartz.oversea.service.JobAndTriggerService;
import hotel.quartz.oversea.util.JobRestTemplateUtils;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.quartz.JobExecutionContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.util.ObjectUtils;
import org.springframework.web.client.RestTemplate;

import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.*;

/**
 * <p>
 *  触发携程接口处理缓存变化数据
 * </p>
 *
 * @description: todo Switchs Get Change Redis Data To Push Job
 * @author: qiuyy
 * @date: 2020-05-26 13:22
 * @version: V1.0
 */
@Slf4j
public class todoSwitchsPopChangeGoodsRedisDataJob implements BaseJob {
    private String timestamp = "Tsgcrdtpj"+String.valueOf(System.currentTimeMillis());

    private String jobGroupName = MeituanConstants.JOB_GROUP_NAME_MT;
    private String jobClassName = this.getClass().getName();

    @Autowired
    private JobAndTriggerService jobAndTriggerService;

    @Autowired
    private RestTemplate restTemplate;
    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private RedisService redisService;

    @Autowired
    private StartMtApiGoodsPriStatUpdateInfoTask startMtApiGoodsPriStatUpdateInfoTask;

    @Autowired
    private SwitchRoomPriceService switchRoomPriceService;

    /**
     * 暂时 2秒一次   触发携程接口处理缓存变化数据
     * @param jobExecutionContext
     */
    @Override
    @SneakyThrows
    public void execute(JobExecutionContext jobExecutionContext) {
        log.info("===========lll值为{}===",redisService.exists("is_open_method"));
        log.info("todo Switchs Get Change Redis Data To Push Job {} >>>>>>>> 触发携程接口处理缓存变化数据定时器 执行时间: {}", timestamp, DateUtil.getCurrTime());
        //缓存存在使用新方案
        if(redisService.exists("is_open_method")){
            log.info("==========执行新方案===========");
            if(0==redisService.queueSize(CommonConstants.SWITCH_CALLBACK_PUSH_DATA_QUEUE)){
                log.info("todo Switchs Get Change Redis Data To Push Job {} >>>>>>>> 队列size=0，定时器不触发，该次定时器跳过: {},{},推送数据的长度为{}",timestamp, DateUtil.getCurrTime(),redisService.queueSize(CommonConstants.SWITCH_CALLBACK_PUSH_DATA_QUEUE));
            }else{
                request();
            }
            request();
        }else{
            log.info("==========执行旧方案===========");
            Boolean zero = false;
            if((0==redisService.queueSize(MeituanConstants.REDIS_CHANGE_GOODS_DATA_MANY_HOTEL))){
                zero = true;
                //////////////电话预警  20210330 qyy//////////////////
                if(null == redisService.get("swmt_pop_change_goods_is_not_find_close")){
                    if(null != redisService.get("swmt_pop_change_goods_is_not_find")){
                        String firstTime = (String)redisService.get("swmt_pop_change_goods_is_not_find");
                        String now = DateUtil.getCurrTime();
                        Long m = DateUtil.dateDiff(firstTime,"min",now,"yyyy-MM-dd HH:mm:ss");
                        if(m.intValue()>=2){
                            log.info("todo Switchs Get Change Redis Data To Push Job {} >>>>>>>> 上次变化价格房态为0，当前批次也为0，时间间隔：m={},firstTime={},now={}",m,firstTime,now);
                            if(null == redisService.get("swmt_pop_change_goods_is_not_find_has_send")){
                                log.info("todo Switchs Get Change Redis Data To Push Job {} >>>>>>>> 上次变化价格房态为0，当前批次也为0，将推送电话预警",m,firstTime,now);
                                SendUtils.sendWarnPhone("时间间隔"+m+"分钟，价格房态变化还是为零，请核实", 2,restTemplate);
                                redisService.setUnit("swmt_pop_change_goods_is_not_find_has_send",1,1L,TimeUnit.HOURS);
                            }
                        }
                    }else{
                        redisService.setUnit("swmt_pop_change_goods_is_not_find", DateUtil.getCurrTime(),180L,TimeUnit.SECONDS);
                    }
                }
            }else{
                //////////////电话预警  20210330 qyy//////////////////
                redisService.remove("swmt_pop_change_goods_is_not_find");
            }
            if(zero){
                log.info("todo Switchs Get Change Redis Data To Push Job {} >>>>>>>> 队列size=0，定时器不触发，该次定时器跳过: {},{},推送数据的长度为{}",timestamp, DateUtil.getCurrTime(),redisService.queueSize(MeituanConstants.REDIS_CHANGE_GOODS_DATA_MANY_HOTEL));
            }else{
                request();
            }
        }
        log.info("todo Switchs Get Change Redis Data To Push Job {} >>>>>>>> 触发携程接口处理缓存变化数据定时器 结束时间: {},{}",timestamp, DateUtil.getCurrTime());

    }

    /**
     * 调用美团接口    主动查询上送的酒店是否存在变动数据，有则接口中操作存入缓存队列
     *
     * @return
     */
    private void request() {
        String callbackHost = CommonUrlConstants.CALLBACK_HOST;
        log.info("todo Switchs Get Change Redis Data To Push Job {} 触发携程接口处理缓存变化数据定时器 进入方法 request",timestamp);
        //发起请求
        Map params = new HashMap();
        Result response;
        long size2;
        //如果缓存有key执行新方案，不存在使用旧方案
        if(redisService.exists("is_open_method")){
            log.info("==========执行新方案===========");
            long size = redisTemplate.opsForList().size(CommonConstants.SWITCH_CALLBACK_PUSH_DATA_QUEUE);
            int checkSize = 100;
            if(null != redisTemplate.opsForValue().get("todoSwitchsGetChangeRedisDataToPushJob_check_size_value")){
                checkSize = (Integer) redisTemplate.opsForValue().get("todoSwitchsGetChangeRedisDataToPushJob_check_size_value");
            }
            if(size>checkSize && null == redisTemplate.opsForValue().get("todoSwitchsGetChangeRedisDataToPushJob_check_size")){
                  SendUtils.dingMsg("定时器处理产品价格房态队列异常！！请关注 ", DateUtil.getCurrTime()+" 队列待消费已超过"+checkSize+"，更新已堆积滞后 ", MessageEnums.genre.GOODS_STATUS_AND_PRICE.getCode(),restTemplate);
                redisTemplate.opsForValue().set("todoSwitchsGetChangeRedisDataToPushJob_check_size",1,15,TimeUnit.MINUTES);
            }
            boolean f=false;
            if(redisService.queueSize(CommonConstants.SWITCH_CALLBACK_PUSH_DATA_QUEUE)>0){
                log.info("===========队列有数据，先进行消耗一波============");
                f=true;
                new Thread(this::pushRoomData).start();
            }
            String checkGetChangeGoodsByOneHotelUrl = callbackHost+ UrlSwitchsEnums.goodsPrice.SWITCH_THREAD_DEAL_REDIS_CHANGE_DATA_2.getValue();
            log.info("todo Switchs Get Change Redis Data To Push Job {} 触发携程接口处理缓存变化数据定时器  调用携程接口前，缓存队列size={}，该size不能作为依据，频繁变动因为 异步和主动同步在push",timestamp,size);
            response= JobRestTemplateUtils.post(checkGetChangeGoodsByOneHotelUrl, JSON.toJSONString(params),restTemplate);
            if(!f){
                log.info("===========队列有数据，进行消耗一波============");
                new Thread(this::pushRoomData).start();
            }
            size2 = redisService.queueSize(CommonConstants.SWITCH_CALLBACK_PUSH_DATA_QUEUE);
        }else{
            log.info("==========执行旧方案===========");
            long size = redisTemplate.opsForList().size(MeituanConstants.REDIS_CHANGE_GOODS_DATA_MANY_HOTEL);
            int checkSize = 100;
            if(null != redisTemplate.opsForValue().get("todoSwitchsGetChangeRedisDataToPushJob_check_size_value")){
                checkSize = (Integer) redisTemplate.opsForValue().get("todoSwitchsGetChangeRedisDataToPushJob_check_size_value");
            }
            if(size>checkSize && null == redisTemplate.opsForValue().get("todoSwitchsGetChangeRedisDataToPushJob_check_size")){
                SendUtils.dingMsg("定时器处理产品价格房态队列异常！！请关注 ", DateUtil.getCurrTime()+" 队列待消费已超过"+checkSize+"，更新已堆积滞后 ", MessageEnums.genre.GOODS_STATUS_AND_PRICE.getCode(),restTemplate);
                redisTemplate.opsForValue().set("todoSwitchsGetChangeRedisDataToPushJob_check_size",1,15,TimeUnit.MINUTES);
            }
            String checkGetChangeGoodsByOneHotelUrl = callbackHost+ UrlSwitchsEnums.goodsPrice.SWITCH_THREAD_DEAL_REDIS_CHANGE_DATA.getValue();
            log.info("todo Switchs Get Change Redis Data To Push Job {} 触发携程接口处理缓存变化数据定时器  调用携程接口前，缓存队列size={}，该size不能作为依据，频繁变动因为 异步和主动同步在push",timestamp,size);
            response= JobRestTemplateUtils.post(checkGetChangeGoodsByOneHotelUrl, JSON.toJSONString(params),restTemplate);
            size2 = redisService.queueSize(MeituanConstants.REDIS_CHANGE_GOODS_DATA_MANY_HOTEL);
        }
        log.info("todo Switchs Get Change Redis Data To Push Job {} 触发携程接口处理缓存变化数据定时器  调用携程接口结束，缓存队列size={}，（该size不能作为依据，频繁变动因为 异步和主动同步在push）",timestamp,size2);
        if(response.getCode()== CommonConstants.SUCCESS){

        }else{
            //还原
            //redisTemplate.opsForList().leftPush(MeituanConstants.REIDS_POP_ALL_SALE_ROOM_ABOUT_MT_HOTEL_IDS,String.valueOf(hotelId));
            log.error("todo Switchs Get Change Redis Data To Push Job {} 触发携程接口处理缓存变化数据定时器进入方法 request 返回失败：{},{}",timestamp, JSON.toJSONString(response), JSON.toJSONString(params));
        }

    }
    /***
    * @Author: lmf
    * @Date: 2021/1/6
     * 消费价格队列中的数据,消费数据
    */
    public void pushRoomData(){
        //线程数量
       String key = CommonConstants.SWITCH_PUSH_ROOM_THREAD_NUM;
        int num = 10;
        long startTime = System.currentTimeMillis();
        if (redisService.exists(key)) {
            num = (int) redisService.get(key);
        } else {
            redisService.set(key, 10);
        }
        ExecutorService executorService = Executors.newFixedThreadPool(num);
        List<Future<Result<Object>>> threads = new ArrayList<>();
        String batchPushRoomDatasVoStr="";
        BatchPushRoomDataVo batchPushRoomDataVo=null;
        log.info("==========缓存队列的长度为{}",redisService.queueSize(CommonConstants.SWITCH_CALLBACK_PUSH_DATA_QUEUE));
        for (int i = 1; i <= num; i++) {
            log.info("========进来了{}====",i);
            synchronized(this){
                batchPushRoomDatasVoStr= (String) redisService.RPop(CommonConstants.SWITCH_CALLBACK_PUSH_DATA_QUEUE);
            }
            log.info("=============batchPushRoomDatasVoStr的值为{}==========",batchPushRoomDatasVoStr);
            batchPushRoomDataVo= GsonUtils.GsonToBean(batchPushRoomDatasVoStr, BatchPushRoomDataVo.class);
            if(ObjectUtils.isEmpty(batchPushRoomDataVo)){
                log.info("==================暂无推送数据====================");
                break;
            }
            executorService.submit(new pushDataThread(batchPushRoomDataVo));
            log.info("===========当前可推送的数据为{}========",batchPushRoomDatasVoStr);
        }
        executorService.shutdown();
        long endTime=System.currentTimeMillis();
        while(true){
            if(executorService.isTerminated()){
                log.info("====执行结束了======");
                break;
            }
        }
        log.info("===========整个推送花费推送花费的时间为{}",(endTime-startTime));
    }
    class pushDataThread implements Callable<Result<Object>> {
        private BatchPushRoomDataVo batchPushRoomDataVo;
        public pushDataThread(BatchPushRoomDataVo batchPushRoomDataVo) {
            this.batchPushRoomDataVo = batchPushRoomDataVo;
        }
        @Override
        public Result<Object> call() throws Exception {
            //6.调用直连推送报价
            log.info("========时间戳为{}推送数据为{}",timestamp, JSON.toJSONString(this.batchPushRoomDataVo.getBatchPushRoomVo()));
            Result<Map<String,String>> result=switchRoomPriceService.batchPushRoomData(this.batchPushRoomDataVo.getBatchPushRoomVo());
            log.info("时间戳为{}pushRoom---result>>>>{}",timestamp,result);
            if(result.getCode()!= CommonConstants.SUCCESS){
                redisService.lPush(CommonConstants.SWITCH_CALLBACK_PUSH_DATA_QUEUE, JSON.toJSONString(this.batchPushRoomDataVo));
            }
            /***
            * @Author: lmf
            * @Date: 2021/1/12
             * 推送钉钉
            */
            String roomId= String.valueOf(this.batchPushRoomDataVo.getBatchPushRoomVo().getRoomDataEntitys().get(0).getRoomId());
            new MsgThread(this.batchPushRoomDataVo.getBatchPushRoomVo().getHotelId(),roomId,this.batchPushRoomDataVo.getTimeStamp(),"时间戳为"+this.batchPushRoomDataVo.getTimeStamp()+result.getMsg().toString()).run();
            return new Result<>();
        }
    }
    /**
     * 异步推送钉钉消息
     */
    class MsgThread implements Runnable{
        private Integer hotelId;
        private String roomIds;
        private String timeStamp;
        private String msg;

        public MsgThread(Integer hotelId, String roomIds, String timeStamp, String msg) {
            this.hotelId = hotelId;
            this.roomIds = roomIds;
            this.timeStamp = timeStamp;
            this.msg = msg;
        }

        @Override
        public void run() {
            //当前操作时间戳
            SimpleDateFormat ds=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            Date date=new Date();
            String time=ds.format(date);
            log.info("===========异步推送给钉钉了=============");
            SendUtils.dingMsgNotLog(time+"直连推送报价等数据接口酒店id"+this.hotelId+"售卖房型id"+this.roomIds,"时间戳为"+timeStamp+"请求状态"+this.msg,1,restTemplate);
            //switchRestTempaleUtilsService.pushSavePopLog(this.hotelId,this.mtHotelId,this.timeStamp);
        }
    }
    /*public void cronJob(String cron,String doTime){
        //已最后一页，暂停定时器,删除rediskey
        JobForm jobForm = new JobForm();
        jobForm.setJobClassName(jobClassName);
        jobForm.setJobGroupName(jobGroupName);
        jobForm.setCronExpression(cron);
        try {
            jobAndTriggerService.cronJob(jobForm);
            log.info("todo Switchs Get Change Redis Data To Push Job 程序触发n"+doTime+"秒后继续执行");
        } catch (Exception e) {
            log.error("todo Switchs Get Change Redis Data To Push Job {} 执行cronJob异常: {}",timestamp,jobForm);
            log.error(e.getMessage(),e);
            try {
                Thread.sleep(5000);
                log.error("todo Switchs Get Change Redis Data To Push Job {} 再次执行cronJob",timestamp);
                jobAndTriggerService.cronJob(jobForm);
            } catch (Exception e2) {
                log.error(e2.getMessage(), e2);
                SendUtils.dingMsg("【异步处理美团房态定时器出现异常，请核实！】", e2.getMessage(),99,restTemplate);
            }
        }
    }*/

}
